home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Shareware Grab Bag
/
Shareware Grab Bag.iso
/
050
/
xref.arc
/
XREF.PAS
< prev
Wrap
Pascal/Delphi Source File
|
1985-06-19
|
28KB
|
934 lines
{$C-} {* essential for programmed pause-abort facility;
see procedure dealwithuser *}
program xrefpas;
(*
Cross reference generator Version 1.10, 5/8/85
------> REQUIRES TURBO PASCAL 3.0 <------
--- (explained below)
******************* NEW PARAGRAPH!!!!!! *********************
Whoops! Looks like there was a bug in the original version which resulted
in page-breaks occurring in the wrong places, especially when include files
were involved. This has been corrected, but who knows what else is wrong.
I hope soon to have an MCI mail box through which I can communicate with
you, my fans out there. In the meantime, prepare those suggestions for
improvements in XREF, or TURBO utilities in general, cause I really get
off on writing these things.
*************************************************************
This program, in its original form, was downloaded off of some bulletin
board somewhere. At that point, it only listed a Pascal program to the
LST device and generated a cross reference of whatever reserved words
were in the list in function rsvdword, with those reserved boldfaced in
the printout. I have made numerous improvements.
The program now optionally lists include files within the source listing.
At any point during listing, printing may be interrupted by pressing any
key, at which point you can either resume the listing or abort.
The listing can be sent to the printer, the screen, or a disk file.
If sent to the screen, reserved appear in reverse video. If output is
to the printer or a file, the screen displays the name of the file being
listed, with include files indented, and the line number of output.
File names supplied by the user, i.e. the file to be listed and optional
output file, are checked by function file_exists, which is cool in that
it does not need to open the file. In fact, there are several subroutines
within this program which would be useful for general purpose TURBO Pascal
programming.
You should note that many of the new functions of XREF use TURBO features
which are specific to the IBM-PC version, such as the reverse video and
use of wherex and wherey.
I can't think of anything else one would need in a source listing program.
If someone else can, or has any questions about the program, please contact
me at this address:
Larry Jay Seltzer
657 Seventh Street
Lakewood, NJ 08701
The compressed and default mode options work for the Epson FX-100 and
any compatable printer. The codes are stored in CONSTants, so as to
be easily changeable for any printer with this capacity. There are three
basic ways to invoke the program:
1) XREF from command line. You will be prompted for everything.
2) XREF [pathname][filename].[ext]
You will be prompted for all applicable parameters.
3) XREF [pathname][filename].[ext] [/ { C, D, F, I, N, S } ]
C means print out in compressed mode (EPSON)
D means print out in default mode
F means print out to disk file
I means list include files within the main
N means exclude the cross refernce
S means send output to the screen instead of printer.
Note that the recursive nature of the actual listing procedure (do_listing)
allows for any nesting level of INCLUDEs, even though TURBO Pascal does not
allow INCLUDEs to be nested. So this is nice, but of questionable value.
The program requires TURBO 3.0 because it uses TURBO FIBs, which have been
altered for version 3.0. The FIB no longer contains the file's date of
creation, so the file handle is passed to DOS function call $57, which
returns the date.
>>>> This should be compiled into a COM file
by Turbo Pascal(tm) 3.0 or later before running.
What Borland hath wrought!!! <<<<
*)
const
ch_per_word = 22; { characters per word }
linenums = 11; { line numbers per printed reference line }
linenum_size = 5; { size of displayed line numbers }
reserved_count = 208; { number of reserved words }
{*** printer control sequences ***}
compressed_on : array[1..1] of char = (#15);
default_on : array[1..2] of char = (#27,#64);
boldface_on : array[1..2] of char = (#27,#69);
boldface_off : array[1..2] of char = (#27,#70);
type
datestr = string[10];
option_type = string[1];
switchsettype = set of char;
wordref = ^word;
itemref = ^item;
word = record key: string[ch_per_word];
first, last: itemref;
left, right: wordref;
end ;
item = record lno: integer;
next: itemref;
end ;
state = (none,symbol,quote,com1,pcom2,com2,pcom2x);
filstring = string[64];
titletype = string[10];
var
filename, incname, outname : filstring;
root: wordref;
m,n,
linenum : integer;
id: string[127];
fv,iv,
outf : text;
f,lastf : char;
switch : char;
switches : switchsettype;
scan, tscan: state;
pageno:integer;
title: titletype;
taken_careof,
parsing_for_dollars,
itsa_directive,
itsan_include : boolean;
cutoff : integer;
function file_exists(var thefile : filstring) : boolean;
type
Registertype = record
AX,BX,CX,DX,
BP,SI,DI,DS,ES,flags: integer;
end;
VAR
registers:registertype;
begin
thefile := thefile + #0;
with registers do
begin
ds := seg(thefile);
dx := ofs(thefile)+1;
ax := $4E00;
cx := $0000
end;
intr($21,registers);
file_exists := not ((registers.flags and $0001) = $0001)
end;
function currdate: DateStr;
type
regpack = record
ax,bx,cx,dx,bp,si,ds,es,flags: integer;
end;
var
recpack: regpack; {record for MsDos call}
month,day: string[2];
year: string[4];
tempdate: datestr;
i,dx,cx: integer;
begin
with recpack do
begin
ax := $2a shl 8;
end;
MsDos(recpack); { call function }
with recpack do
begin
str(cx,year); {convert to string}
str(dx mod 256,day); { " }
str(dx shr 8,month); { " }
end;
tempdate := month+'/'+day+'/'+year;
for i:= 1 to 10 do if tempdate[i] = ' ' then tempdate[i]:= '0';
currdate := tempdate
end;
function filedate(var thefile : text) : datestr;
type
regpack = record
al, ah : byte;
bx,cx,dx,bp,si,ds,es,flags: integer;
end;
var
sortofdate,
i, handle : integer;
month,day : string[2];
year : string[4];
date : datestr;
recpack : regpack;
begin
handle := memw [seg(thefile):ofs(thefile)];
recpack.al := 0;
recpack.AH := $57;
recpack.bx := handle;
msdos(recpack);
sortofdate := recpack.dx;
str(((sortofdate shr 9) + 1980):4,year);
str(((sortofdate shr 5) and $000F):2,month);
str((sortofdate and $001F):2,day);
date:= month + '/' + day + '/' + year;
for i:= 1 to 10 do if date[i] = ' ' then date[i]:= '0';
filedate := date
end; {WhenCreated}
procedure newpage(var fname : filstring;title:titletype);
var date : datestr;
date_stuff : string[40];
begin
pageno := pageno+1;
date_stuff := 'Created '+filedate(fv)+' '+'Listed '+currdate;
If (not ('S' in switches)) and (not ('F' in switches))
then write(outf,#12) else writeln(outf);
write(outf,title,': ',fname,' ':6,date_stuff,' ':6,'Page ',pageno:3);
writeln(outf);
writeln(outf);
end {newpage};
procedure writeid;
var xx : integer;
function rsvdword: boolean;
const
wordlist: array[1..reserved_count] of string[14] =
('ABSOLUTE','ADDR','AND','ARC','ARCTAN','ARRAY','ASSIGN','AUX',
'AUXINPTR','AUXOUTPTR','BACK',
'BEGIN','BLOCKREAD','BLOCKWRITE','BOOLEAN','BYTE',
'CASE','CHAIN','CHAR','CHDIR','CHR','CIRCLE','CLEARSCREEN',
'CLOSE','CLREOL','CLRSCR','COLORTABLE','CON','CONCAT','CONINPTR',
'CONOUTPTR','CONST',
'CONSTPTR','COPY','COS','CRTEXIT','CRTINIT','CSEG','DELAY',
'DELETE','DELLINE','DISPOSE',
'DIV','DO','DOWNTO','DRAW','ELSE','END','END.','EOF','EOLN','ERASE',
'EXECUTE','EXP','EXTERNAL','FALSE','FILE','FILEPOS','FILESIZE',
'FILLCHAR','FILLPATTERN','FILLSCREEN','FILLSHAPE',
'FLUSH','FOR','FORWARD','FRAC','FREEMEM',
'FUNCTION','GETDIR','GETDOT',
'GETMEM','GETPIC','GOTO','GOTOXY',
'GRAPHBACKGROUND','GRAPHCOLORMODE',
'GRAPHMODE','GRAPHWINDOW','HALT','HEAPPTR',
'HEADING','HI','HIDETURTLE',
'HIRES','HIRESCOLOR','HOME',
'IF','IN','INLINE','INPUT','INSERT','INSLINE','INT','INTEGER','INTR',
'IORESULT','KBD','KEYPRESSED','LABEL','LENGTH','LN','LO','LOWVIDEO',
'LST','LSTOUTPTR','MARK','MAXAVAIL',
'MAXINT','MEMAVAIL','MEMW','MKDIR','MOD',
'MOVE','MSDOS','NEW','NIL','NORMVIDEO','NOSOUND',
'NOT','ODD','OF','OFS','OR','ORD','OUTPUT','OVERLAY',
'PACKED','PALETTE','PARAMCOUNT','PARAMSTR','PATTERN',
'PENDOWN','PENUP',
'PI','PLOT','PORT','POS','PRED','PROCEDURE',
'PROGRAM','PTR','PUTPIC','RANDOM','RANDOMIZE','READ','READLN','REAL',
'RECORD','RELEASE','RENAME','REPEAT','RESET',
'REWRITE','RMDIR','ROUND','SEEK','SEEKEOF','SEEKEOLN',
'SEG','SET','SETHEADING','SETPENCOLOR','SETPOSITION',
'SHL','SHOWTURTLE','SHR','SIN','SIZEOF','SOUND',
'SQR','SQRT','STR','STRING',
'SUCC','SWAP','TEXT','TEXTBACKGROUND','TEXTCOLOR','TEXTMODE',
'THEN','TO','TRM','TRUE','TRUNC',
'TURNLEFT','TURNRIGHT','TURTLETHERE','TURTLEWINDOW','TYPE',
'UNTIL','UPCASE','USR','USRINPTR','USROUTPTR','VAL','VAR',
'WHEREX','WHEREY','WHILE','WINDOW',
'WITH','WRAP','WRITE','WRITELN','XCOR','XOR','YCOR');
var
i, j, k: integer;
upid: string[127];
begin
upid := '';
for i := 1 to length(id) do
upid := upid + upcase(copy(id,i,1));
i := 1;
j := reserved_count - 1;
repeat
k := (i+j) div 2;
if upid > wordlist[k] then i := k+1
else j := k
until i = j;
rsvdword := (upid = wordlist[i])
end {rsvdword};
procedure search (var w1: wordref);
var w: wordref;
x: itemref;
begin
w := w1;
if w = nil then
begin
new(w);
new(x);
with w^ do
begin
key := id;
left := nil;
right := nil;
first := x;
last := x
end ;
x^.lno := n;
x^.next := nil;
w1 := w
end
else
if id < w^.key then search(w^.left)
else
if id > w^.key then search(w^.right)
else
begin
new(x);
x^.lno := n;
x^.next := nil;
w^.last^.next := x;
w^.last := x
end
end {search} ;
Procedure Regular_video;
begin
TextBackground(black);
TextColor(white);
end;
Procedure Reverse_video;
begin
TextBackground(white);
TextColor(black);
end;
FUNCTION locase(ch:char) : char;
BEGIN
If ch in ['A'..'Z']
then locase := chr(ord(ch) or $20)
else locase := ch
END;
begin
if rsvdword then
if 'F' in switches
then
write(outf,id)
else
if 'S' in switches
then
begin
reverse_video;
write(outf,id);
regular_video
end
else
write(outf,boldface_on,id,boldface_off)
else
begin
write(outf,id);
If not ('N' in switches)
then
begin
for xx := 1 to length(id) do
id[xx] := locase(id[xx]);
search(root)
end
end
end {writeid};
procedure scrn_update(indent : boolean);
const
mainx = 18;
incx = 20;
begin
if indent
then
gotoxy(incx,wherey)
else
gotoxy(mainx,wherey);
write(n:1)
end;
procedure printtree (w:wordref);
procedure printword (w:word);
var l: integer;
x: itemref;
begin
if (n mod 60) = 0 then
newpage(filename,'xref');
write(outf,' ',w.key:ch_per_word);
x := w.first;
l:= 0;
repeat
if l = linenums then
begin
writeln(outf);
n := n+1;
scrn_update(false);
if (n mod 60) = 0 then
newpage(filename,'xref');
write(outf,' ':ch_per_word+1);
l := 0
end ;
l := l+1;
write(outf,x^.lno:linenum_size);
x := x^.next
until x = nil;
writeln(outf);
n := n+1;
scrn_update(false)
end {printword} ;
begin
if w <> nil then
begin
printtree(w^.left);
printword(w^);
printtree(w^.right)
end
end {printtree} ;
function get_answer(opt1,opt2 : option_type) : option_type;
var ch : char;
begin
repeat
read(kbd,ch)
until ch in [opt1,opt2,upcase(opt1),upcase(opt2)];
writeln(ch);
get_answer := upcase(ch)
end;
function get_choices(opt1,opt2,opt3 : option_type) : option_type;
var ch : char;
begin
repeat
read(kbd,ch)
until ch in [opt1,opt2,opt3,upcase(opt1),upcase(opt2),upcase(opt3)];
writeln(ch);
get_choices := upcase(ch)
end;
procedure empty_keyboard;
var
c : char;
begin
while keypressed do
read(kbd,c)
end;
Procedure do_listing(var fv : text;title:titletype ;
fn : filstring ; mode : state);
procedure bugout;
begin
parsing_for_dollars := false;
itsan_include := false;
itsa_directive := false
end;
procedure dealwithuser;
var
oldx,oldy : integer;
answer : option_type;
c : char;
begin
empty_keyboard;
oldx:=wherex; oldy:=wherey;
writeln;
write('Press space to continue, Esc to abort ...');
answer := get_answer(#32,#27);
if answer=#27 then halt
else
begin
gotoxy(wherex,wherey-1);
delline;
if (oldy=25) or (oldy=23)
then oldy := 23;
gotoxy(oldx,oldy)
end
end;
procedure isitan_include;
begin
while f=' ' do
begin
write(outf,f);
read(fv,f)
end;
incname:='';
repeat
incname :=incname + f;
read(fv,f);
write(outf,f)
until not (f in ['.','A'..'Z','a'..'z','_','0'..'9']);
if pos('.',incname)=0 then incname := incname + '.PAS';
cutoff := n;
assign(iv,incname);
if not ('S' in switches)
then
begin
writeln;writeln;
write(' Listing include file ',incname);
if 'F' in switches
then writeln(' to file ',outname)
else writeln;
write(' Processing line #')
end;
newpage(incname,'Include');
taken_careof := true;
do_listing(iv,'Include',incname,none);
newpage(fn,title);
cutoff := n;
taken_careof := true;
close(iv);
if not ('S' in switches)
then
begin
writeln;writeln;
write('Listing main file ',filename);
if 'F' in switches
then writeln(' to file ',outname)
else writeln;
write('Processing line #')
end;
parsing_for_dollars := false;
itsa_directive := false;
itsan_include := false;
end;
begin
cutoff := n;
scan := mode;
parsing_for_dollars := false;
itsa_directive := false;
itsan_include := false;
reset(fv);
if title='Main'
then newpage(fn,title);
while not eof(fv) do
begin
if (n-(60+cutoff)) = 0
then
begin
cutoff := cutoff+60;
if not taken_careof then
newpage(fn,title)
end;
taken_careof := false;
n := n+1;
if not ('S' in switches)
then
scrn_update(title='Include');
write(outf,n:linenum_size,' ');
while not eoln(fv) do
begin
if keypressed
then dealwithuser;
read(fv,f);
case scan of
none: begin
if f in['a'..'z','A'..'Z','_'] then
begin
id := f;
scan := symbol
end
else
begin
write(outf,f);
if f = '''' then scan := quote
else
if f = '{' then
begin
scan := com1;
If 'I' in switches then parsing_for_dollars := true
end
else
if f = '(' then scan := pcom2
end
end;
symbol: begin
if f in['.','a'..'z','A'..'Z','0'..'9','_'] then
begin
id := id + f;
end
else
begin
writeid;
write(outf,f);
if f = '''' then scan := quote
else
if f = '{' then
begin
scan := com1;
if 'I' in switches then parsing_for_dollars := true
end
else
if f = '(' then scan := pcom2
else
scan := none
end
end;
quote: begin
write(outf,f);
if f = '''' then scan := none
end;
com1: begin
write(outf,f);
if (f='+') or (f='-')
then bugout;
If itsan_include
then
begin
isitan_include;
f:='}'
end;
If itsa_directive
then
if (f = 'I') or (f='i')
then
begin
itsan_include := true;
itsa_directive := false
end
else
itsa_directive := false;
If parsing_for_dollars
then
if f = '$'
then
begin
parsing_for_dollars :=false;
itsa_directive := true
end
else
parsing_for_dollars := false;
if f = '}' then
begin
parsing_for_dollars := false;
itsa_directive := false;
itsan_include := false;
scan := none
end
end;
pcom2: begin
if f in['a'..'z','A'..'Z','_'] then
begin
id := f;
scan := symbol
end
else
begin
write(outf,f);
if f = '''' then scan := quote
else
if f = '{' then
begin
scan := com1;
if 'I' in switches then parsing_for_dollars := true
end
else
if f = '(' then scan := pcom2
else
if f = '*' then
begin
scan := com2;
if 'I' in switches then parsing_for_dollars := true
end
else
scan := none
end
end;
com2: begin
write(outf,f);
if (f='+') or (f='-')
then bugout;
If itsan_include
then
begin
isitan_include;
f:='}'
end;
If itsa_directive
then
if (f = 'I') or (f='i')
then
begin
itsan_include := true;
itsa_directive := false
end
else
itsa_directive := false;
If parsing_for_dollars
then
if f = '$'
then
begin
itsa_directive := true;
parsing_for_dollars := false
end
else
parsing_for_dollars := false;
if f = '*' then
scan := pcom2x
else
if (f = ')') and (lastf='*')
then
begin
parsing_for_dollars := false;
itsa_directive := false;
itsan_include := false;
scan := none
end
end;
pcom2x: begin
write(outf,f);
if (f = ')')
then scan := none
else
begin
scan := com2;
lastf:=f
end
end;
end;
end;
if scan = symbol then
begin
writeid;
scan := none
end;
writeln(outf);
readln(fv);
end
end;
procedure get_info;
var
i : integer;
parameters : string[127] absolute cseg:$0080;
workparams : string[127];
procedure get_filename;
begin
M := 0;
repeat
M := M+1
until (M > length(workparams)) or (workparams[M] <> ' ');
N:=M;
REPEAT
N:=N+1
UNTIL (N>length(workparams)) OR (workparams[N]='/');
filename := copy(workparams,m,(n-m))
end;
procedure waytogo_user; {* filename and switches on command line *}
begin
n := pos('/',workparams) + 1;
While n<=length(workparams) do
begin
if upcase(workparams[n]) in ['C','D','F','I','N','S']
then switches := switches + [upcase(workparams[n])];
n:=n+1
end
end;
procedure query_filename;
begin
write('Enter name of file to be listed [.PAS] : ');
readln(filename);
if pos('.',filename)=0
then filename := filename + '.PAS'
end;
procedure switch_menu;
var answer : char;
begin
write('Output to file, screen, or printer (F,S,P) ? ');
answer := get_choices('f','s','p');
If answer = 'P'
then
begin
write('Printer output in compressed or default mode (C,D) ? ');
if get_answer('c','d') = 'C'
then switches := switches + ['C']
else switches := switches + ['D']
end
else
if answer='S'
then switches := switches + ['S']
else
begin
switches := switches + ['F'];
write('Enter name of output file [',copy(filename,1,
pos('.',filename)-1),'.','LST]');
readln(outname);
if outname=''
then outname := copy(filename,1,pos('.',filename)-1)+'.'+'LST'
end;
write('List Include files within the Main listing (Y,N) ? ');
if get_answer('y','n') = 'Y'
then switches := switches + ['I'];
write('Produce cross reference of user-defined identifiers (Y,N) ? ');
if get_answer('y','n') = 'N'
then switches := switches + ['N'];
end;
begin
workparams := parameters;
{ while workparams[LENGTH(workparams)]=#0 DO
delete(workparams,length(workparams),1);}
If pos('/',workparams)>0 then
If pos('/',workparams)<=length(workparams) then
begin
get_filename;
if not file_exists(filename)
then
begin
writeln('File ',filename,' not found.');
repeat
query_filename;
if not file_exists(filename)
then writeln('File ',filename,' not found.');
until file_exists(filename);
switch_menu
end
else
waytogo_user
end
else
begin
get_filename;
if not file_exists(filename)
then
begin
writeln('File ',filename,' not found.');
repeat
query_filename
until file_exists(filename);
end;
switch_menu
end
else
begin
if length(workparams)=0
then query_filename
else get_filename;
if not file_exists(filename)
then
begin
writeln('File ',filename,' not found.');
repeat
query_filename;
if not file_exists(filename)
then writeln('File ',filename,' not found.')
until file_exists(filename);
end;
switch_menu
end;
while filename[LENGTH(filename)]=#0 DO
delete(filename,length(filename),1)
end;
begin {*** main ***}
switches := [];
lastf:=' '; {*** to prevent an error; see CASE scan of com2,pcom2x ***}
get_info;
empty_keyboard;
if (not ('F' in switches)) and (not ('S' in switches))
then
begin
If 'C' in switches
then writeln(lst,compressed_on);
If 'D' in switches
then writeln(lst,default_on)
end;
if 'S' in switches
then
begin
assign(outf,'CON:');
rewrite(outf)
end
else
if 'F' in switches
then
begin
assign(outf,outname);
rewrite(outf)
end
else
begin
assign(outf,'LST:');
rewrite(outf)
end;
root := nil;
n := 0;
cutoff := 0;
scan := none;
pageno := 0;
title := 'Main';
if not ('S' in switches)
then
begin
writeln;
write('Listing main file ',filename);
if 'F' in switches
then writeln(' to file ',outname)
else writeln;
write('Processing line #')
end;
assign(fv,filename);
do_listing(fv,title,filename,none);
if not ('N' in switches)
THEN
BEGIN
if not ('S' in switches)
then
begin
writeln;
write('Listing cross reference of ',filename);
if 'F' in switches
then writeln(' to file ',outname)
else writeln;
write('Processing line #')
end;
n := 0;
pageno := 0;
title := 'xref';
printtree(root);
If (not ('S' in switches)) and (not ('F' in switches))
then write(outf,#12)
END
end.